package com.chenyun.rpc.feign.config;

import feign.Client;
import feign.Feign;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory;
import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;

/**
 * 配置okhttp3
 *
 * @author: Lonni
 * @date: 2024/1/19 0019 11:08
 */
@Configuration
@ConditionalOnClass(Feign.class)
@ConditionalOnProperty(value = "chenyun.rpc.type", havingValue = "feign", matchIfMissing = true)
@AutoConfigureAfter(value = FeignAutoConfiguration.class)
@ConditionalOnExpression(value = "${feign.okhttp.enabled}")
@Slf4j
public class FeignOkHttpConfig implements Serializable {

    public FeignOkHttpConfig() {
        log.info("加载FeignOkHttpConfig...");
    }

    @Bean
    @ConditionalOnMissingBean({Client.class})
    public Client feignClient(okhttp3.OkHttpClient client) {
        log.info("初始化okhttp3.OkHttpClient");
        return new feign.okhttp.OkHttpClient(client);
    }

    @Bean
    @ConditionalOnMissingBean(ConnectionPool.class)
    public ConnectionPool httpClientConnectionPool(
            FeignHttpClientProperties httpClientProperties,
            OkHttpClientConnectionPoolFactory connectionPoolFactory) {
        log.info("初始化okhttp3-> ConnectionPool");
        Integer maxTotalConnections = httpClientProperties.getMaxConnections();
        Long timeToLive = httpClientProperties.getTimeToLive();
        TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
        return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
    }

    @Bean
    public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
                                       ConnectionPool connectionPool,
                                       FeignHttpClientProperties httpClientProperties) {
        log.info("初始化okhttp3-> client");

        Boolean followRedirects = httpClientProperties.isFollowRedirects();
        Integer connectTimeout = httpClientProperties.getConnectionTimeout();
        Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
        OkHttpClient okHttpClient = httpClientFactory.createBuilder(disableSslValidation)
                .connectTimeout((long) connectTimeout, TimeUnit.MILLISECONDS)
                .followRedirects(followRedirects)
                .connectionPool(new ConnectionPool())
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        //这个chain里面包含了request和response，所以你要什么都可以从这里拿
                        Request request = chain.request();
                        long t1 = System.nanoTime();//请求发起的时间
                        log.info(String.format("发送请求 %s on %s%n%s",
                                request.url(), chain.connection(), request.headers()));
                        Response response = chain.proceed(request);
                        long t2 = System.nanoTime();//收到响应的时间
                        //这里不能直接使用response.body().string()的方式输出日志
                        //因为response.body().string()之后，response中的流会被关闭，程序会报错，我们需要创建出一
                        //个新的response给应用层处理
                        ResponseBody responseBody = response.peekBody(1024 * 1024);
                        log.info(String.format("接收响应: [%s] %n返回json:【%s】 %.1fms%n%s",
                                response.request().url(),
                                responseBody.string(),
                                (t2 - t1) / 1e6d,
                                response.headers()));
                        return response;
                    }
                })
                .build();
    log.info("初始化okHttp完成,当前connectionCount为:{},idleConnectionCount:{}",okHttpClient.connectionPool().connectionCount()
            ,okHttpClient.connectionPool().idleConnectionCount());
        return okHttpClient;


    }


}



